<template>
  <div class="rule-container">
    <div class="toolbar">
      <el-button type="primary" @click="openDialog('add')">新增停车计费规则</el-button>
      <el-button @click="exportToExcel">导出Excel</el-button>
    </div>

    <el-table :data="ruleList" style="width: 100%">
      <el-table-column type="index" label="序号" />
      <el-table-column label="计费规则编号" prop="ruleNumber" />
      <el-table-column label="计费规则名称" prop="ruleName" />
      <el-table-column label="免费时长(分钟)" prop="freeDuration" />
      <el-table-column label="收费上限(元)" prop="chargeCeiling" />
      <el-table-column label="计费方式">
        <template #default="scope">
          {{ formatChargeType(scope.row.chargeType) }}
        </template>
      </el-table-column>
      <el-table-column label="计费规则" prop="ruleNameView" />
      <el-table-column label="操作" fixed="right" width="120" align="center">
        <template #default="scope">
          <el-button size="mini" type="text" @click="openDialog('edit', scope.row)">编辑</el-button>
          <el-button size="mini" type="text" @click="deleteRule(scope.row.id)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>

    <el-dialog :visible.sync="dialogVisible" width="680px" :title="dialogMode === 'add' ? '新增规则' : '编辑规则'" @close="handleDialogClose">
      <el-form ref="ruleForm" :model="ruleForm" :rules="ruleFormRules" label-position="top">
        <el-form-item label="计费规则编号" prop="ruleNumber">
          <el-input v-model="ruleForm.ruleNumber" />
        </el-form-item>

        <el-form-item label="计费规则名称" prop="ruleName">
          <el-input v-model="ruleForm.ruleName" />
        </el-form-item>

        <el-form-item label="计费方式" prop="chargeType">
          <el-radio-group v-model="ruleForm.chargeType" size="small">
            <el-radio label="duration" border>时长收费</el-radio>
            <el-radio label="turn" border>按次收费</el-radio>
            <el-radio label="partition" border>分段收费</el-radio>
          </el-radio-group>
        </el-form-item>

        <div class="flex-container">
          <el-form-item label="免费时长(分钟)" prop="freeDuration">
            <el-input v-model="ruleForm.freeDuration" type="text" @input="sanitizeInput('freeDuration')" />
          </el-form-item>

          <el-form-item label="收费上限(元)" prop="chargeCeiling">
            <el-input v-model="ruleForm.chargeCeiling" type="text" @input="sanitizeInput('chargeCeiling')" />
          </el-form-item>
        </div>

        <el-form-item label="计费规则" required>
          <template v-if="ruleForm.chargeType === 'duration'">
            <DurationRule :form="ruleForm" @sanitize="sanitizeInput" />
          </template>
          <template v-if="ruleForm.chargeType === 'turn'">
            <TurnRule :form="ruleForm" @sanitize="sanitizeInput" />
          </template>
          <template v-if="ruleForm.chargeType === 'partition'">
            <PartitionRule :form="ruleForm" @sanitize="sanitizeInput" />
          </template>
        </el-form-item>
      </el-form>

      <template #footer>
        <el-button size="mini" @click="closeDialog">取 消</el-button>
        <el-button size="mini" type="primary" @click="confirmAddOrEdit">{{ dialogMode === 'add' ? '确 定' : '保存' }}</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import { getRuleListAPI, createRuleAPI, deleteRuleAPI, updateRuleAPI, getRuleDetailAPI } from '@/api/car'
import { utils, writeFileXLSX } from 'xlsx'
import DurationRule from './components/DurationRule.vue'
import TurnRule from './components/TurnRule.vue'
import PartitionRule from './components/PartitionRule.vue'

export default {
  name: 'ParkingRule',
  components: {
    DurationRule,
    TurnRule,
    PartitionRule
  },
  data() {
    return {
      ruleList: [], // 规则列表数据
      dialogVisible: false, // 控制对话框显示/隐藏
      dialogMode: 'add', // 对话框模式，'add' 新增，'edit' 编辑
      ruleForm: { // 规则表单数据
        ruleNumber: '', // 计费规则编号
        ruleName: '', // 计费规则名称
        chargeType: 'duration', // 计费类型，默认是时长收费
        chargeCeiling: null, // 收费上限
        freeDuration: null, // 免费时长
        durationTime: null, // 时长计费时间
        durationPrice: null, // 时长计费价格
        durationType: 'hour', // 时长计费类型，默认是小时
        turnPrice: null, // 按次收费价格
        partitionFrameTime: null, // 分段时间
        partitionFramePrice: null, // 分段费用
        partitionIncreaseTime: null, // 增加时间
        partitionIncreasePrice: null // 增加费用
      },
      ruleFormRules: { // 表单验证规则
        ruleNumber: [{ required: true, message: '请输入规则编号', trigger: 'blur' }], // 规则编号必填
        ruleName: [{ required: true, message: '请输入规则名称', trigger: 'blur' }], // 规则名称必填
        chargeType: [{ required: true, message: '请选择收费类型', trigger: 'blur' }], // 收费类型必选
        freeDuration: [
          { required: true, message: '请输入免费时长', trigger: 'blur' }, // 免费时长必填
          { type: 'number', message: '免费时长必须为数字', trigger: 'blur' }
        ],
        chargeCeiling: [
          { required: true, message: '请输入收费上限', trigger: 'blur' }, // 收费上限必填
          { type: 'number', message: '收费上限必须为数字', trigger: 'blur' }
        ],
        durationTime: [
          { required: true, message: '请输入时长计费时间', trigger: 'blur' }, // 时长计费时间必填
          { type: 'number', message: '时长计费时间必须为数字', trigger: 'blur' }
        ],
        durationPrice: [
          { required: true, message: '请输入时长计费价格', trigger: 'blur' }, // 时长计费价格必填
          { type: 'number', message: '时长计费价格必须为数字', trigger: 'blur' }
        ],
        turnPrice: [
          { required: true, message: '请输入按次收费价格', trigger: 'blur' }, // 按次收费价格必填
          { type: 'number', message: '按次收费价格必须为数字', trigger: 'blur' }
        ],
        partitionFrameTime: [
          { required: true, message: '请输入分段时间', trigger: 'blur' }, // 分段时间必填
          { type: 'number', message: '分段时间必须为数字', trigger: 'blur' }
        ],
        partitionFramePrice: [
          { required: true, message: '请输入分段费用', trigger: 'blur' }, // 分段费用必填
          { type: 'number', message: '分段费用必须为数字', trigger: 'blur' }
        ],
        partitionIncreaseTime: [
          { required: true, message: '请输入增加时间', trigger: 'blur' }, // 增加时间必填
          { type: 'number', message: '增加时间必须为数字', trigger: 'blur' }
        ],
        partitionIncreasePrice: [
          { required: true, message: '请输入增加费用', trigger: 'blur' }, // 增加费用必填
          { type: 'number', message: '增加费用必须为数字', trigger: 'blur' }
        ]
      }
    }
  },
  computed: {
    formattedFormData() {
      // 计算属性：格式化表单数据，确保数值字段是数字类型
      const data = { ...this.ruleForm }
      const numericFields = ['freeDuration', 'chargeCeiling', 'durationTime', 'durationPrice', 'turnPrice', 'partitionFrameTime', 'partitionFramePrice', 'partitionIncreaseTime', 'partitionIncreasePrice']

      numericFields.forEach(field => {
        if (data[field] !== null && data[field] !== undefined) {
          data[field] = Number(data[field])
        }
      })

      return data
    }
  },
  created() {
    // 组件创建时，获取规则列表
    this.getRuleList()
  },
  methods: {
    // 这个方法用来过滤输入，只允许输入数字
    sanitizeInput(field) {
      // 1. 检查字段是否为空或未定义
      if (this.ruleForm[field] === null || this.ruleForm[field] === undefined) {
        return
      }
      // 2. 确保值是字符串类型再调用 replace 方法
      this.ruleForm[field] = String(this.ruleForm[field]).replace(/[^0-9]/g, '') || null
    },
    // 这个方法用来打开对话框
    async openDialog(mode, row = null) {
      // 1. 设置对话框模式
      this.dialogMode = mode
      // 2. 显示对话框
      this.dialogVisible = true

      if (mode === 'edit' && row) {
        // 3. 如果是编辑模式，则获取规则详情
        try {
          // 4. 调用 API 获取规则详情
          const res = await getRuleDetailAPI(row.id)
          // 5. 更新表单数据
          this.ruleForm = { ...res.data, id: row.id }
          // 6. 清理所有输入框
          this.sanitizeAllInputs()
        } catch (error) {
          console.error('获取规则详情失败:', error)
          // 7. 如果获取失败，则使用列表中的数据
          this.ruleForm = { ...row }
          // 8. 设置默认值
          this.setDefaultValues()
        }
      } else {
        // 9. 如果是新增模式，则重置表单
        this.resetForm()
      }
    },
    // 这个方法用来设置默认值
    setDefaultValues() {
      // 1. 如果计费类型是 "时长收费" (duration)
      if (this.ruleForm.chargeType === 'duration') {
        // 2. 如果未设置 durationTime，则默认为 '1'
        if (!this.ruleForm.durationTime) this.ruleForm.durationTime = '1'
        // 3. 如果未设置 durationPrice，则默认为 '5'
        if (!this.ruleForm.durationPrice) this.ruleForm.durationPrice = '5'
      } else if (this.ruleForm.chargeType === 'turn') { // 4. 如果计费类型是 "按次收费" (turn)
        // 5. 如果未设置 turnPrice，则默认为 '10'
        if (!this.ruleForm.turnPrice) this.ruleForm.turnPrice = '10'
      } else if (this.ruleForm.chargeType === 'partition') { // 6. 如果计费类型是 "分段收费" (partition)
        // 7. 如果未设置 partitionFrameTime，则默认为 '1'
        if (!this.ruleForm.partitionFrameTime) this.ruleForm.partitionFrameTime = '1'
        // 8. 如果未设置 partitionFramePrice，则默认为 '2'
        if (!this.ruleForm.partitionFramePrice) this.ruleForm.partitionFramePrice = '2'
        // 9. 如果未设置 partitionIncreaseTime，则默认为 '3'
        if (!this.ruleForm.partitionIncreaseTime) this.ruleForm.partitionIncreaseTime = '3'
        // 10. 如果未设置 partitionIncreasePrice，则默认为 '4'
        if (!this.ruleForm.partitionIncreasePrice) this.ruleForm.partitionIncreasePrice = '4'
      }
    },
    // 这个方法用来重置输入框
    sanitizeAllInputs() {
      // 1. 定义需要清理的数值字段
      const numericFields = ['freeDuration', 'chargeCeiling', 'durationTime', 'durationPrice', 'turnPrice', 'partitionFrameTime', 'partitionFramePrice', 'partitionIncreaseTime', 'partitionIncreasePrice']
      // 2. 遍历每个字段并调用 sanitizeInput 方法
      numericFields.forEach(field => {
        this.sanitizeInput(field)
      })
    },
    // 这个方法用来重置表单
    resetForm() {
      // 1. 重置表单数据
      this.ruleForm = {
        ruleNumber: '',
        ruleName: '',
        chargeType: 'duration',
        chargeCeiling: null,
        freeDuration: null,
        durationTime: null,
        durationPrice: null,
        durationType: 'hour',
        turnPrice: null,
        partitionFrameTime: null,
        partitionFramePrice: null,
        partitionIncreaseTime: null,
        partitionIncreasePrice: null
      }
      // 2. 使用可选链避免表单未渲染时出错
      this.$refs.ruleForm?.resetFields()
    },
    // 这个方法用来关闭对话框
    closeDialog() {
      // 1. 隐藏对话框
      this.dialogVisible = false
      // 2. 重置表单
      this.resetForm()
    },
    // 这个方法用来确认新增或编辑
    async confirmAddOrEdit() {
      // 1. 验证表单
      this.$refs.ruleForm.validate(async valid => {
        if (valid) {
          try {
            // 2. 构造请求数据
            const payload = { ...this.formattedFormData, id: this.ruleForm.id }
            console.log('提交的数据:', payload)

            // 3. 如果是新增模式
            if (this.dialogMode === 'add') {
              // 4. 调用 API 创建规则
              await createRuleAPI(payload)
              // 5. 提示成功
              this.$message.success('添加成功')
            } else { // 6. 如果是编辑模式
              // 7. 调用 API 更新规则
              await updateRuleAPI(payload)
              // 8. 提示成功
              this.$message.success('编辑成功')
            }

            // 9. 隐藏对话框
            this.dialogVisible = false
            // 10. 刷新列表
            setTimeout(() => {
              this.getRuleList()
            }, 500)
          } catch (error) {
            // 11. 提示失败
            this.$message.error(`操作失败: ${error.message || '请重试'}`)
            console.error('API error:', error)
          }
        }
      })
    },
    // 这个方法用来删除规则
    async deleteRule(id) {
      // 1. 弹出确认框
      await this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      })

      // 2. 调用删除 API
      await deleteRuleAPI(id)

      // 3. 提示成功
      this.$message.success('删除成功!')

      // 4. 刷新列表
      this.getRuleList()
    },
    // 这个方法用来格式化收费类型
    formatChargeType(type) {
      // 1. 定义收费类型映射
      const TYPEMAP = {
        'turn': '按次收费',
        'duration': '按时长收费',
        'partition': '分段收费'
      }
      // 2. 返回格式化后的收费类型
      return TYPEMAP[type]
    },
    // 这个方法用来导出到 Excel
    async exportToExcel() {
      // 1. 获取规则列表数据
      const res = await getRuleListAPI(this.params)
      // 2. 定义表格表头键和值
      const tableHeaderKeys = ['ruleNumber', 'ruleName', 'freeDuration', 'chargeCeiling', 'chargeType', 'ruleNameView']
      const tableHeaderValues = ['计费规则编号', '计费规则名称', '免费时长(分钟)', '收费上限(元)', '计费方式', '计费规则']

      // 3. 构造表格数据
      const sheetData = res.data.rows.map(item => {
        const obj = {}
        tableHeaderKeys.forEach(key => {
          obj[key] = key === 'chargeType' ? this.formatChargeType(item[key]) : item[key]
        })
        return obj
      })

      // 4. 创建工作表
      const worksheet = utils.json_to_sheet(sheetData)
      // 5. 创建工作簿
      const workbook = utils.book_new()
      // 6. 将工作表添加到工作簿
      utils.book_append_sheet(workbook, worksheet, 'Data')
      // 7. 添加表头
      utils.sheet_add_aoa(worksheet, [tableHeaderValues], { origin: 'A1' })

      // 8. 设置列宽
      const columnWidths = [20, 20, 15, 15, 20, 30]
      worksheet['!cols'] = columnWidths.map(width => ({ wch: width }))

      // 9. 设置表头样式
      tableHeaderValues.forEach((_, index) => {
        const cellAddress = utils.encode_cell({ c: index, r: 0 })
        if (worksheet[cellAddress]) {
          worksheet[cellAddress].s = {
            font: { bold: true },
            alignment: { horizontal: 'center' },
            border: {
              top: { style: 'thin' },
              bottom: { style: 'thin' },
              left: { style: 'thin' },
              right: { style: 'thin' }
            }
          }
        }
      })

      // 10. 设置单元格边框
      const range = utils.decode_range(worksheet['!ref'])
      for (let R = range.s.r; R <= range.e.r; ++R) {
        for (let C = range.s.c; C <= range.e.c; ++C) {
          const cellAddress = utils.encode_cell({ c: C, r: R })
          if (worksheet[cellAddress]) {
            worksheet[cellAddress].s = worksheet[cellAddress].s || {}
            worksheet[cellAddress].s.border = {
              top: { style: 'thin' },
              bottom: { style: 'thin' },
              left: { style: 'thin' },
              right: { style: 'thin' }
            }
          }
        }
      }

      // 11. 写入 Excel 文件
      writeFileXLSX(workbook, 'SheetJSVueAoO.xlsx')
    },
    // 这个方法用来获取规则列表
    async getRuleList() {
      // 1. 打印日志
      console.log('正在刷新规则列表...')
      // 2. 调用 API 获取规则列表
      const { data: { rows }} = await getRuleListAPI(this.params)
      // 3. 打印获取到的规则列表
      console.log('获取到的规则列表:', rows)
      // 4. 更新规则列表数据
      this.ruleList = rows
    },
    // 这个方法用来处理对话框关闭事件
    handleDialogClose() {
      // 1. 重置表单
      this.resetForm()
    }
  }
}
</script>

<style lang="scss" scoped>
.rule-container {
  padding: 20px;
  background-color: #fff;
}

.toolbar {
  margin-bottom: 20px;
}

.flex-container {
  display: flex;
  gap: 20px;

  .el-form-item {
    flex: 1;
  }
}
</style>
